#include "utils/DbPool/DbConnectionPool.hpp"
#include <muduo/base/Logging.h>
using namespace http::db;

void DbConnectionPool::initialize(const std::string &host, const std::string &user, const std::string &password, const std::string &database, size_t poolSize)
{
    // 初始化连接池 注意连接池会被多个线程使用 所以需要加锁 防止重复初始化
    std::lock_guard<std::mutex> lock(_mutex);
    if (_initialized)
    {
        throw DbException("DbConnectionPool has already been initialized");
    }
    _host = host;
    _user = user;
    _password = password;
    _database = database;

    for (size_t i = 0; i < poolSize; ++i)
    {
        _connectionQueue.push(createConnection());
    }

    _initialized = true;
    LOG_INFO << "DbConnectionPool initialized, poolSize: " << poolSize;
}

std::shared_ptr<DbConnection> DbConnectionPool::getConnection()
{
    std::shared_ptr<DbConnection> connection;
    {
        std::unique_lock<std::mutex> lock(_mutex);
        while (_connectionQueue.empty())
        {
            if (!_initialized)
            {
                throw DbException("DbConnectionPool has not been initialized");
            }
            LOG_INFO << "Waiting for available connection...";
            _cv.wait(lock);
        }

        connection = _connectionQueue.front();
        _connectionQueue.pop();
    }

    try
    {
        // 在锁外检查连接是否有效
        if (!connection->ping())
        {
            // 连接无效 则重新连接
            LOG_WARN << "Connection lost, try to reconnect";
            connection->reconnect();
        }
        // 连接有效 则返回连接
        return std::shared_ptr<DbConnection>(connection.get(), [this, connection](DbConnection *)
                                             {
            std::lock_guard<std::mutex> lock(_mutex);
            _connectionQueue.push(connection);
            _cv.notify_one(); });
    }
    catch (const std::exception &e)
    {
        LOG_ERROR << "Failed to get connection: " << e.what();
        {
            // 连接获取失败 则将连接放回连接池
            std::lock_guard<std::mutex> lock(_mutex);
            _connectionQueue.push(connection);
            _cv.notify_one(); // 通知其他线程有连接可用
        }
        throw;
    }
}

DbConnectionPool::DbConnectionPool()
{
    _checkThread = std::thread(&DbConnectionPool::checkConnection, this);
    _checkThread.detach(); // 分离线程 主线程结束后 线程也会结束
}

DbConnectionPool::~DbConnectionPool()
{
    std::lock_guard<std::mutex> lock(_mutex);
    while (!_connectionQueue.empty())
    {
        _connectionQueue.pop();
    }
    LOG_INFO << "DbConnectionPool destroyed";
}

std::shared_ptr<DbConnection> DbConnectionPool::createConnection()
{
    return std::make_shared<DbConnection>(_host, _user, _password, _database);
}

// 检查连接
void DbConnectionPool::checkConnection()
{
    while (1)
    {
        try
        {
            std::vector<std::shared_ptr<DbConnection>> connsToCheck;
            {
                std::lock_guard<std::mutex> lock(_mutex);
                if (_connectionQueue.empty())
                {
                    // 连接队列为空 则等待1秒后继续检查
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                    continue;
                }
                // 连接队列不为空 则检查所有连接
                while (!_connectionQueue.empty())
                {
                    // 从连接队列中取出连接 并检查连接是否有效
                    auto connection = _connectionQueue.front();
                    connsToCheck.push_back(connection);
                    _connectionQueue.pop();
                }
            }

            // 锁外检查连接是否有效
            for (auto &connection : connsToCheck)
            {
                if (!connection->ping())
                {
                    try
                    {
                        connection->reconnect();
                    }
                    catch (const std::exception &e)
                    {
                        LOG_ERROR << "Failed to reconnect: " << e.what();
                    }
                }
            }

            // 检查完成后 休眠60秒再进行下次检查
            std::this_thread::sleep_for(std::chrono::seconds(60));
        }
        catch (const std::exception &e)
        {
            // 检查线程异常 则等待5秒后继续检查
            LOG_ERROR << "Connection check thread error: " << e.what();
            std::this_thread::sleep_for(std::chrono::seconds(5));
        }
    }
}
